package com.tocean.app.exception;

import com.tocean.app.dto.response.BaseResponse;
import com.tocean.app.dto.response.BaseResponseCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.yaml.snakeyaml.constructor.DuplicateKeyException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@RestControllerAdvice
public class NxFrameworkGlobalException {

    private static final String BAD_REQUEST_MSG = "客户端请求参数错误;";

//    /**
//     * 未认证异常处理
//     *
//     * @param exception
//     * @return
//     */
//    @ExceptionHandler(value = UnauthenticatedException.class)
//    @ResponseStatus(HttpStatus.OK)
//    public ApiResult<Boolean> unauthenticatedExceptionHandler(UnauthenticatedException exception) {
//        printRequestDetail();
//        printApiCodeException(ApiCode.UNAUTHENTICATED_EXCEPTION, exception);
//        return ApiResult.fail(ApiCode.UNAUTHENTICATED_EXCEPTION);
//    }
//
//    /**
//     * 未授权异常处理
//     *
//     * @param exception
//     * @return
//     */
//    @ExceptionHandler(value = UnauthorizedException.class)
//    @ResponseStatus(HttpStatus.OK)
//    public ApiResult<Boolean> unauthorizedExceptionHandler(UnauthorizedException exception) {
//        printRequestDetail();
//        printApiCodeException(ApiCode.UNAUTHORIZED_EXCEPTION, exception);
//        return ApiResult.fail(ApiCode.UNAUTHORIZED_EXCEPTION);
//    }

    /**
     * 功能描述：找不到资源(未找到处理器异常)
     *
     * @param exception
     * @return
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ResponseEntity<BaseResponse> noHandlerFoundExceptionHander(NoHandlerFoundException exception) {
        return ResponseEntity.ok(BaseResponse.failure(HttpStatus.NOT_FOUND.value(), "路径不存在，请检查路径是否正确"));
    }

    @ExceptionHandler(NxFrameworkException.class)
    @ResponseStatus(HttpStatus.OK)
    public ResponseEntity<BaseResponse> nxFrameworkException(Exception e) {
        log.error("NxFramework 错误异常 [{}], [{}]", e.getMessage(), e);
        return ResponseEntity.ok(BaseResponse.failure(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage()));
    }

    /**
     * <1> 处理 form data方式调用接口校验失败抛出的异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(BindException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public ResponseEntity<BaseResponse> bindExceptionHandler(BindException e) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();

        String errorMsg = fieldErrors.stream()
                .map(o -> o.getDefaultMessage())
                .collect(Collectors.joining(";"));

        return ResponseEntity.ok(BaseResponse.failure(BaseResponseCode.VALID_CODE, BAD_REQUEST_MSG + errorMsg));
    }

    /**
     * <2> 处理 json 请求体调用接口校验失败抛出的异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public ResponseEntity<BaseResponse> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();

        String errorMsg = fieldErrors.stream()
                .map(o -> o.getDefaultMessage())
                .collect(Collectors.joining(";"));

        return ResponseEntity.ok(BaseResponse.failure(BaseResponseCode.VALID_CODE, BAD_REQUEST_MSG + errorMsg));
    }

    /**
     * <3> 处理单个参数校验失败抛出的异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public ResponseEntity<BaseResponse> constraintViolationExceptionHandler(ConstraintViolationException e) {
        Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();

        String errorMsg = constraintViolations.stream()
                .map(o -> o.getMessage())
                .collect(Collectors.joining(";"));

        return ResponseEntity.ok(BaseResponse.failure(BaseResponseCode.VALID_CODE, BAD_REQUEST_MSG + errorMsg));
    }

    @ExceptionHandler(DuplicateKeyException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public ResponseEntity<BaseResponse> handleDuplicateKeyException(DuplicateKeyException e) {
        return ResponseEntity.ok(BaseResponse.failure(HttpStatus.INTERNAL_SERVER_ERROR.value(), "数据重复，请检查后提交"));
    }

    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public ResponseEntity<BaseResponse> IllegalArgumentException(IllegalArgumentException e) {
        return ResponseEntity.ok(BaseResponse.failure(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage()));
    }

//    /**
//     * 功能描述：请求方式错误
//     *
//     * @param exception
//     * @return
//     */
//    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
//    public ResponseEntity<Result> httpRequestMethodNotSupportedExceptionHandler(Exception exception) {
//        return new ResponseEntity<>(new Result().serverError("请求方式错误"), HttpStatus.BAD_REQUEST);
//    }

//    /**
//     * 功能描述：controller参数异常/缺少
//     *
//     * @param exception
//     * @return
//     */
//    @ExceptionHandler({
//            MissingServletRequestParameterException.class,
//            MethodArgumentTypeMismatchException.class,
//            RequestRejectedException.class
//    })
//    public ResponseEntity<Result> missingServletRequestParameterException(Exception exception) {
//        return new ResponseEntity<>(new Result().serverError("参数异常"), HttpStatus.INTERNAL_SERVER_ERROR);
//    }

//    /**
//     * 功能描述：单次上传文件过大
//     *
//     * @param exception
//     * @return
//     */
//    @ExceptionHandler(MaxUploadSizeExceededException.class)
//    public ResponseEntity<Result> maxUploadSizeExceededException(Exception exception) {
//        return new ResponseEntity<>(new Result().serverError("文件过大"), HttpStatus.INTERNAL_SERVER_ERROR);
//    }

    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public ResponseEntity<BaseResponse> businessException(BusinessException e) {
        log.error("NxFrameworkGlobalException 错误异常 [{}], [{}]", e.getMessage(), e);
        return ResponseEntity.ok(BaseResponse.failure(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage()));
    }


    /**
     * 功能描述：捕捉控制器里面自己抛出的所有异常
     *
     * @param request
     * @param ex
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(value = HttpStatus.OK)
    public ResponseEntity<BaseResponse> globalException(HttpServletRequest request, Throwable ex) {
        log.error(ex.getMessage(), ex);

        return ResponseEntity.ok(BaseResponse.failure(getStatus(request).value(), "服务异常，请联系管理员"));
    }

    private HttpStatus getStatus(HttpServletRequest request) {
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        if (statusCode == null) {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }

        return HttpStatus.valueOf(statusCode);
    }

}
